library ieee;
use ieee.std_logic_1164.all;

ENTITY table IS
    PORT (clock, reset, Forwarding_to_Table_ACK : IN STD_LOGIC;
          Forwarding_to_Table_srcPort : IN STD_LOGIC_VECTOR(1 downto 0);
          Forwarding_to_Table_srcAddress, Forwarding_to_Table_desAddress: IN STD_LOGIC_VECTOR(47 downto 0);
		  full,writing, shifting, match, prematch: OUT STD_LOGIC;
          write_location, shift_destination: OUT STD_LOGIC_VECTOR(31 downto 0);
          --, locate_in_reg, out_locate
		  out_test: OUT STD_LOGIC_VECTOR(31 downto 0);
          --reads: OUT STD_LOGIC_VECTOR(31 downto 0);
          state: OUT STD_LOGIC_VECTOR(4 downto 0);
          add: OUT STD_LOGIC_VECTOR(47 downto 0);
          searchadd: OUT STD_LOGIC_VECTOR(47 downto 0);
          firstsearchport: OUT STD_LOGIC_VECTOR(1 downto 0); 
		  --preport: OUT STD_LOGIC_VECTOR(2 downto 0);
          Table_to_Forwarding_Port: OUT STD_LOGIC_VECTOR(2 downto 0); 
          Table_to_Forwarding_ACK, Table_to_Forwarding_Valid  : OUT STD_LOGIC);
END table;

architecture structural of table is

component logicblock IS
    PORT (clock, reset, input, match, table_full_in : IN STD_LOGIC;
          location: IN STD_LOGIC_VECTOR(31 downto 0);
          state: OUT STD_LOGIC_VECTOR(4 downto 0);
          read_en, outputpulse, ack, compare_write, port_write,output_write,table_write, table_shift,add_choose, update_location_en, shift_direction, table_full, write_choose, tablestart, port_write_choose, shift_full: OUT STD_LOGIC);
END component;

component shift_table is
	port(clock,ctrl_writeEN,ctrl_shiftEN,ctrl_reset :in std_logic;
		ctrl_writeReg,ctrl_readReg,ctrl_shiftReg :in std_logic_vector(0 to 31);
		data_searchaddr : in std_logic_vector(0 to 47);
		data_inaddr : in std_logic_vector(0 to 47);
		data_inport : in std_logic_vector(0 to 1);
		data_outport: out std_logic_vector(0 to 1);
		data_location: out std_logic_vector(0 to 31);
		data_found: out std_logic);
end component;

component port_in IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (1 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (1 DOWNTO 0)
	);
END component;

component port_out IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (2 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (2 DOWNTO 0)
	);
END component; 

component sa_in IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (47 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (47 DOWNTO 0)
	);
END component; 

component da_in IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (47 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (47 DOWNTO 0)
	);
END component;

component address_in_mux IS
	PORT
	(
		data0x		: IN STD_LOGIC_VECTOR (47 DOWNTO 0);
		data1x		: IN STD_LOGIC_VECTOR (47 DOWNTO 0);
		sel		: IN STD_LOGIC ;
		result		: OUT STD_LOGIC_VECTOR (47 DOWNTO 0)
	);
END component;

component match_found_reg IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC ;
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC 
	);
END component;

component location_reg IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (31 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (31 DOWNTO 0)
	);
END component;

component port_hold_reg IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC_VECTOR (2 DOWNTO 0);
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (2 DOWNTO 0)
	);
END component;

component port_choose IS
	PORT
	(
		data0x		: IN STD_LOGIC_VECTOR (2 DOWNTO 0);
		data1x		: IN STD_LOGIC_VECTOR (2 DOWNTO 0);
		sel		: IN STD_LOGIC ;
		result		: OUT STD_LOGIC_VECTOR (2 DOWNTO 0)
	);
END component;

component LRshift is
		PORT (clock, reset, enable, left_shift, firstentry: IN STD_LOGIC;
			output, shifted_value: OUT STD_LOGIC_VECTOR(31 downto 0)
		);
END component;

component table_full_mux IS
	PORT
	(
		data0x		: IN STD_LOGIC_VECTOR (31 DOWNTO 0);
		data1x		: IN STD_LOGIC_VECTOR (31 DOWNTO 0);
		sel		: IN STD_LOGIC ;
		result		: OUT STD_LOGIC_VECTOR (31 DOWNTO 0)
	);
END component;

component  port_write_choose IS
	PORT
	(
		data0x		: IN STD_LOGIC_VECTOR (1 DOWNTO 0);
		data1x		: IN STD_LOGIC_VECTOR (1 DOWNTO 0);
		sel		: IN STD_LOGIC ;
		result		: OUT STD_LOGIC_VECTOR (1 DOWNTO 0)
	);
END component;

component table_full_reg IS
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		data		: IN STD_LOGIC ;
		enable		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC 
	);
END component;

signal read_enable,table_write_en, table_shift_en, match_found, compare_write, match_value, outport_write, add_choose, port_write, update_location_en, shift_direction, tablefull, write_choose, firstentry_choose, portwritechoose, port_compare, table_full, shift_full: STD_LOGIC;
signal in_port,output_port, chosen_in_port: STD_LOGIC_VECTOR(1 downto 0);
signal possible_port,held_port, port_to_fwd: STD_LOGIC_VECTOR(2 downto 0);
signal stateout: STD_LOGIC_VECTOR(4 downto 0);
--signal state: STD_LOGIC_VECTOR(3 downto 0);
--signal out_test: STD_LOGIC_VECTOR(31 downto 0);
signal write_dest,read_dest,shift_dest, match_reg, location_value : STD_LOGIC_VECTOR(31 downto 0);
signal in_sa,in_da,compare_add,in_add: STD_LOGIC_VECTOR(47 downto 0);

begin

control_logic: logicblock port map(clock,reset,Forwarding_to_Table_ACK, match_value, table_full, write_dest, state, read_enable, Table_to_Forwarding_Valid, Table_to_Forwarding_ACK, compare_write, port_write, outport_write, table_write_en, table_shift_en, add_choose, update_location_en, shift_direction, tablefull, write_choose, firstentry_choose, portwritechoose, shift_full);

in_port_reg: port_in port map(reset, clock, Forwarding_to_Table_srcPort, read_enable, in_port);
in_sa_reg: sa_in port map(reset, clock, Forwarding_to_Table_srcAddress, read_enable, in_sa);
in_da_reg: da_in port map(reset, clock, Forwarding_to_Table_desAddress, read_enable, in_da); 

in_mux: address_in_mux port map(in_sa,in_da,add_choose,compare_add);    

found_reg: match_found_reg port map(reset, clock, match_found, compare_write, match_value);
--port_match_reg: match_found_reg port map(reset, clock, port_compare, match_port_write, port_match);
location: location_reg port map(reset, clock, match_reg, compare_write, location_value);
port_holder: port_hold_reg port map(reset, clock, possible_port, port_write, held_port); 
port_chooser: port_choose port map("111",held_port,match_value,port_to_fwd);
port_out_reg: port_out port map(reset, clock, port_to_fwd, outport_write, Table_to_Forwarding_Port);
write_port_choose: port_write_choose port map(in_port, held_port(1 downto 0), portwritechoose, chosen_in_port);


location_shift: LRshift port map(clock, reset, update_location_en, shift_direction, firstentry_choose, write_dest, out_test);
fullmux: table_full_mux port map(location_value, "10000000000000000000000000000000", shift_full, shift_dest);
table_fullreg: table_full_reg port map(reset, clock, '1', tablefull, table_full);


read_dest<=location_value;

full<=table_full;
shift_destination<=shift_dest;
write_location<=write_dest;
--locate_in_reg<=location_value;
writing<= table_write_en;
shifting<= table_shift_en;
match<= match_value;
prematch<=match_found;
add<=in_add;
--out_locate<=match_reg;
firstsearchport<= chosen_in_port;
--preport<= port_to_fwd;
--reads<=read_dest;
searchadd<= compare_add;

writing_mux: address_in_mux port map(in_sa, in_da, write_choose, in_add);    
shift_reg: shift_table port map(clock, table_write_en, table_shift_en, reset, write_dest, read_dest, shift_dest,compare_add,in_add, chosen_in_port, output_port, match_reg, match_found); 

--port_compare<= ((output_port(1) XNOR in_sa(1)) AND (output_port(0) XNOR in_sa(0)));

possible_port<= '0' & output_port; 

end structural; 